﻿#region Copyright(C) 2010-2010 NCS Pte. Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2010 NCS Pte. Ltd. All rights reserved.
//
// SYSTEM NAME	    : iConnect .Net Application Framework
// COMPONENT ID	    : NCS.IConnect.Core.Wcf
// COMPONENT DESC   : Core components for WCF.	
//
// CREATED DATE/BY  : 18 Aug 2010 / Gao Ye
//
// REVISION HISTORY :	
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using NCS.IConnect.Core.Utilities;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Xml;


namespace NCS.IConnect.Core.Wcf.Compression
{
    /// <summary>
    /// The custom <see cref="MessageEncodingBindingElement"/> used for message compression.
    /// </summary>
    public sealed class CompressedTextMessageEncodingBindingElement: MessageEncodingBindingElement
    {
        /// <summary>
        /// When overridden in a derived class, gets or sets the message version that can be handled by the message encoders produced by the message encoder factory.
        /// </summary>
        /// <returns>The <see cref="T:System.ServiceModel.Channels.MessageVersion"/> used by the encoders produced by the message encoder factory.</returns>
        public override MessageVersion MessageVersion
        {
            get{ return this.InnerBindingElement.MessageVersion;}
            set{this.InnerBindingElement.MessageVersion = value;}
        }

        /// <summary>
        /// Gets the inner binding element.
        /// </summary>
        public TextMessageEncodingBindingElement InnerBindingElement { get; private set; }        

        /// <summary>
        /// Gets the compressor.
        /// </summary>
        public Compressor Compressor { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="CompressedTextMessageEncodingBindingElement"/> class.
        /// </summary>
        /// <param name="innerMessageEncodingElement">The inner message encoding element.</param>
        /// <param name="compressor">The compressor.</param>
        public CompressedTextMessageEncodingBindingElement(TextMessageEncodingBindingElement innerMessageEncodingElement, Compressor compressor)
        {
            Guard.ArgumentNotNull(innerMessageEncodingElement, "innerMessageEncodingElement");
            Guard.ArgumentNotNull(compressor, "compressor");

            this.InnerBindingElement = innerMessageEncodingElement;
            this.Compressor = compressor;
        }

        /// <summary>
        /// When overridden in a derived class, creates a factory for producing message encoders.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.ServiceModel.Channels.MessageEncoderFactory"/> used to produce message encoders.
        /// </returns>
        public override MessageEncoderFactory CreateMessageEncoderFactory()
        {
            return new CompresssedMessageEncoderFactory(this.InnerBindingElement.CreateMessageEncoderFactory(), this.Compressor);
        }

        /// <summary>
        /// When overridden in a derived class, returns a copy of the binding element object.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.ServiceModel.Channels.BindingElement"/> object that is a deep clone of the original.
        /// </returns>
        public override BindingElement Clone()
        {
            TextMessageEncodingBindingElement textEncodingBindingElement = new TextMessageEncodingBindingElement();
            textEncodingBindingElement.MaxReadPoolSize = this.InnerBindingElement.MaxReadPoolSize;
            textEncodingBindingElement.MaxWritePoolSize = this.InnerBindingElement.MaxWritePoolSize;
            textEncodingBindingElement.MessageVersion = this.InnerBindingElement.MessageVersion;
            textEncodingBindingElement.ReaderQuotas = new XmlDictionaryReaderQuotas();
            textEncodingBindingElement.ReaderQuotas.MaxArrayLength = this.InnerBindingElement.ReaderQuotas.MaxArrayLength;
            textEncodingBindingElement.ReaderQuotas.MaxBytesPerRead = this.InnerBindingElement.ReaderQuotas.MaxBytesPerRead;
            textEncodingBindingElement.ReaderQuotas.MaxDepth = this.InnerBindingElement.ReaderQuotas.MaxDepth;
            textEncodingBindingElement.ReaderQuotas.MaxNameTableCharCount = this.InnerBindingElement.ReaderQuotas.MaxNameTableCharCount;
            textEncodingBindingElement.ReaderQuotas.MaxStringContentLength = this.InnerBindingElement.ReaderQuotas.MaxStringContentLength;
            textEncodingBindingElement.WriteEncoding = this.InnerBindingElement.WriteEncoding;
            return new CompressedTextMessageEncodingBindingElement(textEncodingBindingElement, this.Compressor);
        }

        /// <summary>
        /// Gets the property.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public override T GetProperty<T>(BindingContext context)
        {
            if (typeof(T) == typeof(XmlDictionaryReaderQuotas))
            {
                return InnerBindingElement.GetProperty<T>(context);
            }
            else
            {
                return base.GetProperty<T>(context);
            }
        }

        /// <summary>
        /// Builds the channel factory.
        /// </summary>
        /// <typeparam name="TChannel">The type of the channel.</typeparam>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
        {
            Guard.ArgumentNotNull(context, "context");
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelFactory<TChannel>();
        }

        /// <summary>
        /// Builds the channel listener.
        /// </summary>
        /// <typeparam name="TChannel">The type of the channel.</typeparam>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
        {
            Guard.ArgumentNotNull(context, "context");
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelListener<TChannel>();
        }

        /// <summary>
        /// Determines whether this instance [can build channel listener] the specified context.
        /// </summary>
        /// <typeparam name="TChannel">The type of the channel.</typeparam>
        /// <param name="context">The context.</param>
        /// <returns>
        ///   <c>true</c> if this instance [can build channel listener] the specified context; otherwise, <c>false</c>.
        /// </returns>
        public override bool CanBuildChannelListener<TChannel>(BindingContext context)
        {
            Guard.ArgumentNotNull(context, "context");
            context.BindingParameters.Add(this);
            return context.CanBuildInnerChannelListener<TChannel>();
        }        
    }
}
